package com.three.box.network

import android.provider.Settings
import android.util.Log
import com.alibaba.fastjson2.JSON
import com.alibaba.fastjson2.JSONObject
import com.google.gson.Gson
import com.google.gson.reflect.TypeToken
import com.hjq.toast.Toaster
import com.tencent.mmkv.MMKV
import com.three.box.R
import com.three.box.base.BoxApp
import com.three.box.config.Constant
import com.three.box.entity.ApiResult
import com.three.box.entity.Box
import com.three.box.entity.Group
import com.three.box.entity.LoginResult
import com.three.box.entity.OperateType
import com.three.box.entity.ProductConfig
import com.three.box.entity.ProductConfigResult
import com.three.box.network.kt.ApiServiceFactory
import com.three.box.network.kt.AppApiService
import com.three.box.network.kt.AppHost
import kotlinx.coroutines.CompletableDeferred
import kotlinx.coroutines.Deferred
import retrofit2.Call
import retrofit2.Callback
import retrofit2.Response

class AppRepository private constructor() {
    companion object {
        private const val TAG = "AppRepository"
        val instance: AppRepository by lazy {
            AppRepository()
        }
    }

    private val service = ApiServiceFactory.createAPIService(AppHost.AppApi, AppApiService::class.java)
    private val mmkv = MMKV.defaultMMKV()

    val productConfigList = mutableListOf<ProductConfig>()
    val productGroupList = mutableListOf<Group>()

    fun resetConfig() {
        productConfigList.forEach { productConfig ->
            productConfig.checked = false
            productConfig.productModels.forEach { productModel ->
                productModel.checked = false
            }
        }
    }

    suspend fun loginOrRegister(account: String, password: String): Boolean {
        var login = login(account, password).await()
        val errno = login.first

        if (errno == ApiResult.SUCCESS) { // 该账号已经绑定其他设备
            Toaster.show(R.string.login_success)
            return true
        } else if (errno == 710) { // 该账号已经绑定其他设备
            Toaster.show(login.second)
        } else if (errno == 709) { // 该账号未绑定设备
            val register = register(account, password).await()
            if (register.first == ApiResult.SUCCESS) {
                login = login(account, password).await()
                if (login.first == ApiResult.SUCCESS) {
                    Toaster.show(R.string.login_success)
                    return true
                } else {
                    Toaster.show(login.second)
                }
            }
        } else {
            Toaster.show(login.second)
        }

        return false
    }

    private fun login(account: String, password: String): Deferred<Pair<Int, String>> {
        val deviceId = Settings.System.getString(
            BoxApp.instance().contentResolver, Settings.Secure.ANDROID_ID
        )
        val body = JSONObject()
        body["phone"] = account
        body["password"] = password
        body["deviceId"] = deviceId
        val call = service.login(body)
        val deferred = CompletableDeferred<Pair<Int, String>>()
        call.enqueue(object : Callback<ApiResult<LoginResult>> {
            override fun onResponse(
                call: Call<ApiResult<LoginResult>>,
                response: Response<ApiResult<LoginResult>>
            ) {
                val result = response.body()
                Log.d(TAG, result?.data?.toString() ?: "")
                val errno = result?.errno ?: -1
                if (errno == ApiResult.SUCCESS) {
                    // success
                    val loginResult = response.body()?.data
                    val cache = Gson().toJson(loginResult)
                    val mmkv = MMKV.defaultMMKV()
                    mmkv.encode(Constant.LOGIN_RESULT, cache)
                    mmkv.encode(Constant.TOKEN, loginResult?.token)
                    deferred.complete(Pair(ApiResult.SUCCESS, ""))
                } else {
                    deferred.complete(Pair(errno, result?.errmsg ?: ""))
                    Log.d(TAG, "error, ${response.body()?.errmsg}")
                }
            }

            override fun onFailure(call: Call<ApiResult<LoginResult>>, t: Throwable) {
                t.printStackTrace()
                deferred.complete(Pair(ApiResult.FAILURE, t.message ?: ""))
            }
        })
        return deferred
    }

    private fun register(account: String, password: String): Deferred<Pair<Int, String>> {
        val deviceId = Settings.System.getString(
            BoxApp.instance().contentResolver, Settings.Secure.ANDROID_ID
        )
        val body = JSONObject()
        body["phone"] = account
        body["password"] = password
        body["deviceId"] = deviceId
        val call = service.register(body)
        val deferred = CompletableDeferred<Pair<Int, String>>()
        call.enqueue(object : Callback<ApiResult<LoginResult>> {
            override fun onResponse(
                call: Call<ApiResult<LoginResult>>,
                response: Response<ApiResult<LoginResult>>
            ) {
                val result = response.body()
                Log.d(TAG, result?.data?.toString() ?: "")
                val errno = result?.errno ?: -1
                if (errno == ApiResult.SUCCESS) {
                    // success
//                    val loginResult = response.body()?.data
//                    val cache = Gson().toJson(loginResult)
//                    val mmkv = MMKV.defaultMMKV()
//                    mmkv.encode(Constant.LOGIN_RESULT, cache)
                    deferred.complete(Pair(ApiResult.SUCCESS, ""))
                } else {
                    deferred.complete(Pair(errno, result?.errmsg ?: ""))
                    Log.d(TAG, "error, ${response.body()?.errmsg}")
                }
            }

            override fun onFailure(call: Call<ApiResult<LoginResult>>, t: Throwable) {
                t.printStackTrace()
                deferred.complete(Pair(ApiResult.FAILURE, t.message ?: ""))
            }
        })
        return deferred
    }

    fun configInfo(callback: (code: Int, msg: String) -> Unit) {
        val call = service.configInfo()
        call.enqueue(object : Callback<ApiResult<ProductConfigResult>> {
            override fun onResponse(
                call: Call<ApiResult<ProductConfigResult>>,
                response: Response<ApiResult<ProductConfigResult>>
            ) {
                Log.d(TAG, response.body()?.data?.toString() ?: "")
                if (response.body()?.errno == ApiResult.SUCCESS) {
                    // success
                    val configList = response.body()?.data?.productList
                    val groupList = response.body()?.data?.groupList
                    configList?.let { productConfigList.addAll(it) }
                    groupList?.let { productGroupList.addAll(it) }
                    mmkv.encode(Constant.CONFIG_LIST, JSON.toJSONString(productConfigList))
                    mmkv.encode(Constant.GROUP_LIST, JSON.toJSONString(productGroupList))
                    callback.invoke(0, "")
                } else {
                    Log.d(TAG, "error, ${response.body()?.errmsg}")
                    callback.invoke(-1, "内部错误，请联系管理员")
                }
            }

            override fun onFailure(call: Call<ApiResult<ProductConfigResult>>, t: Throwable) {
                t.printStackTrace()
            }
        })
    }

    fun boxInfo(boxId: String, onBoxLoaded: (code: Int, box: Box?) -> Unit) {
        val call = service.boxInfo(boxId)
        call.enqueue(object : Callback<ApiResult<Box>> {
            override fun onResponse(
                call: Call<ApiResult<Box>>,
                response: Response<ApiResult<Box>>
            ) {
                Log.d(TAG, response.body()?.data?.toString() ?: "")
                if (response.body()?.errno == ApiResult.SUCCESS) {
                    // success
//                    Toaster.show("设备注册成功")
                    onBoxLoaded.invoke(0, response.body()?.data)
                } else {
                    Log.d(TAG, "error, ${response.body()?.errmsg}")
                    onBoxLoaded.invoke(-1, null)
                }
            }

            override fun onFailure(call: Call<ApiResult<Box>>, t: Throwable) {
                t.printStackTrace()
                onBoxLoaded.invoke(-1, null)
            }
        })
    }

    fun saveBox(boxObj: JSONObject, saveCallback: (code: Int, msg: String) -> Unit) {
        val call = service.saveBox(boxObj)
        call.enqueue(object : Callback<ApiResult<String>> {
            override fun onResponse(
                call: Call<ApiResult<String>>,
                response: Response<ApiResult<String>>
            ) {
                if (response.body()?.errno == ApiResult.SUCCESS) {
                    // success
                    saveCallback.invoke(ApiResult.SUCCESS, "数据保存成功")
                } else {
                    Log.d(TAG, "error, ${response.body()?.errmsg}")
                }
            }

            override fun onFailure(call: Call<ApiResult<String>>, t: Throwable) {
                saveCallback.invoke(ApiResult.FAILURE, "数据保存失败")
                t.printStackTrace()
            }
        })
    }

    fun loadOperateType(): List<OperateType> {
        val temp = mmkv.decodeString(Constant.OPERATE_TYPE)
        if (temp.isNullOrEmpty()) {
            return listOf()
        }
        val type = object : TypeToken<ArrayList<OperateType>>(){}.type
        return Gson().fromJson<ArrayList<OperateType>>(temp, type)
    }

    /**
     * 获取出入库类型
     * @param type 1 入库 2 出库
     */
    fun reloadOperateType(type: Int) {
        val call = service.operateType(type)
        call.enqueue(object : Callback<ApiResult<List<OperateType>>> {
            override fun onResponse(
                call: Call<ApiResult<List<OperateType>>>,
                response: Response<ApiResult<List<OperateType>>>
            ) {
                val apiResult = response.body()
                if (apiResult?.errno == ApiResult.SUCCESS) {
                    val list = apiResult.data
                    val existList = loadOperateType().toMutableList()
                    if (existList.isEmpty()) {
                        mmkv.encode(Constant.OPERATE_TYPE, Gson().toJson(list))
                    } else {
                        var changed = false
                        list.forEach {
                            if (!existList.contains(it)) {
                                existList.add(it)
                                changed = true
                            }
                        }
                        if (changed) {
                            mmkv.encode(Constant.OPERATE_TYPE, Gson().toJson(existList))
                        }
                    }
                } else {
                    Log.d(TAG, "error, ${apiResult?.errmsg}")
                }
            }

            override fun onFailure(call: Call<ApiResult<List<OperateType>>>, t: Throwable) {
//                Toaster.show("数据保存失败")
                t.printStackTrace()
            }
        })
    }
}